import json
import os
import string
from time import sleep
import pandas as pd
import pypinyin
import requests
import yaml
from shutil import copyfile
from jsonpath import jsonpath


def caseconfig():
    """读取caseconf.yml文件"""
    return yaml.safe_load(open('../config/caseconf.yml', 'r', encoding='utf8'))


def pinyin(word):
    """
    把汉字转化为拼音字母
    :param word 需转化的汉字
    """
    s = ''
    for i in pypinyin.pinyin(word, style=pypinyin.NORMAL):
        s += ''.join(i)
    return s


def read_excel_to_cases(excel_dir):
    """
    将excel用例读出为列表 如[[case1],[case2]]
    :param excel_dir excel文件位置
    """
    df = pd.read_excel(excel_dir)
    # 填充为空的单元格
    df.fillna('', inplace=True)
    # print(df)
    cases = []
    for index in df.index:
        # 单元格行索引 + 前10列
        cases.append([index + 2] + list(df.loc[index].values[0:10]))
    return cases


# 清空测试用例
def clear_cases():
    """
    清除test_cases目录下除run.py以外的文件
    """
    for root, _, files in os.walk('../test_cases'):
        for file in files:
            if file != 'run.py':
                os.remove(root + '/' + file)


def clear_cases_excel():
    """
    清空case_excel
    """
    for root, _, files in os.walk('../case_result'):
        for file in files:
            os.remove(root + '/' + file)


def sed_req(url, method, header, params, pararm_type, export):
    """
    发送请求
    :param url:请求地址
    :param method:请求方法 POST or GET
    :param header:请求头 json类型
    :param params:请求参数 json类型
    :param pararm_type:参数类型 json or form
    :param export: 要导出的参数 json类型
    :return r：响应 e：导出参数的字典
    """
    try:
        header_ = json.loads(header)
    except:
        print('header格式不正确')
    try:
        params_ = json.loads(params)
    except:
        print('params格式不正确')
    try:
        export_ = json.loads(export)
    except:
        export_ = ''

    if method.upper() == 'GET':
        if pararm_type.upper() == 'JSON':
            r = requests.get(url, headers=header_, json=params_, timeout=20)
        else:
            r = requests.get(url, headers=header_, params=params_, timeout=20)
    elif method.upper() == 'POST':
        if pararm_type.upper() == 'JSON':
            r = requests.post(url, headers=header_, json=params_, timeout=20)
        elif pararm_type.upper() == 'FORM':
            r = requests.post(url, headers=header_, data=params_, timeout=20)
        else:
            print('消息体类型不正确')
    else:
        print('请求方法不正确')
    sleep(0.1)
    e = {}
    # 通过jsonpath找到要导出的变量，并写入字典
    if export_:
        for k, v in export_.items():
            if jsonpath(r.json(), v):
                e[k] = jsonpath(r.json(), v)[0]
    r.encoding = 'utf-8'
    return r, e


def assert_in(response, code, asserts):
    """
    根据断言判断是否在返回消息体中
    :param response: request的返回
    :param code: 响应码
    :param asserts: 断言，逗号分隔
    :return: is_pass 断言是否通过  info不通过的原因+response.text
    """
    asserts_ = str(asserts).split(',')
    # print(asserts_)
    # print(response.text)
    is_pass = True
    info = ''
    for a in asserts_:
        try:
            assert response.status_code == code
            assert a in response.text
        except:
            is_pass = False
            info = f'{a} 不在响应结果中' + '\n'
    info = info + response.text
    return is_pass, info


def case_creater(excel_and_casename: dict):
    """
    {"用户模块.xlsx":"test_demo.py"}
    根据casedemo.txt 来在testcase文件夹下生成相应的test文件,并替换文件中的响应内容
    :param excel_and_casename excel和测试用例的组合 通过case_name_creater产生

    """
    # {"用户模块.xlsx":"test_demo.py"}

    for e, c in excel_and_casename.items():
        case_dir = '../test_cases/' + c
        need_template = {'excelname': e, 'classname': pinyin(c).split('.')[0].title(), 'funcname': pinyin(c).split('.')[0]}
        with open('../util/casedemo.txt', 'r', encoding='utf8')as f:
            case_info = f.read()
            t = string.Template(case_info)
            case_info2 = t.substitute(need_template)
            with open(case_dir, 'w', encoding='utf8')as f2:
                f2.write(case_info2)


def case_name_creater():
    """
    生成Excel和测试用例的组合
    会根据caseconfig.yml来决定读哪些文件，未空读所有文件
    生成的是 dict 如{"excel.xlsx":"test_excel.py"}
    """
    case_excels = caseconfig().get('run')
    case_names = []
    # 长度为0遍历case_excel下所有文件
    if not len(case_excels):
        for root, dirs, files in os.walk('../case_excel'):
            for file in files:
                case_excels = files
                case_names.append('test_' + file.split('.')[0] + '.py')

        return dict(zip(case_excels, case_names))
    # 非0根据配置来
    elif len(case_excels):
        for file in case_excels:
            case_names.append('test_' + file.split('.')[0] + '.py')
        return dict(zip(case_excels, case_names))


def template(stra: str, d: dict):
    """
    模板替换
    :param stra:需要被替换的字符串
    :param d: 需要来替换字符串的字典
    :return  替换好的字符串
    """
    t = string.Template(stra)
    return t.safe_substitute(d)


def case_result_creater():
    """
    生成需要跑的测试用例的复制
    """
    for c in case_name_creater().keys():
        source = '../case_excel/' + c
        target = '../case_result/' + c
        copyfile(source, target)


def before_start():
    """
    测试前准备工作
    :return: True or False
    """
    try:
        # 清空case
        clear_cases()
        # 清空case_excel
        clear_cases_excel()
        # 生成测试用例
        case_creater(case_name_creater())
        case_result_creater()
        return True
    except:
        return False


if __name__ == '__main__':
    # case_creater({'用户模块.xlsx': 'test_1.py'})
    # # print(pinyin('哈哈哈.xlsx'))
    # print(case_name_creater().keys())
    # for c in case_name_creater().keys():
    #     source = '../case_excel/' + c
    #     target = '../case_result/' + c
    #     copyfile(source, target)
    before_start()
    # clear_cases()
    # print(read_excel_to_cases('../case_excel/用户模块.xlsx'))
    # case_creater(case_name_creater())
